package com.wawei.seeds.utils;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.util.Log;
import android.widget.ImageView;

import com.bumptech.glide.BitmapRequestBuilder;
import com.bumptech.glide.Glide;
import com.bumptech.glide.RequestManager;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool;
import com.bumptech.glide.load.model.GlideUrl;
import com.bumptech.glide.load.model.ModelCache;
import com.bumptech.glide.load.model.stream.BaseGlideUrlLoader;
import com.bumptech.glide.load.model.stream.StreamResourceLoader;
import com.bumptech.glide.load.model.stream.StreamUriLoader;
import com.bumptech.glide.load.resource.bitmap.BitmapTransformation;
import com.bumptech.glide.request.RequestListener;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Created by parker on 14/12/31.
 */
public class ImageLoader {
    private static final String TAG = "ImageLoader";
    private static final ModelCache<String, GlideUrl> urlCache = new ModelCache<String, GlideUrl>(150);

    private RequestManager.ImageModelRequest<String> mGlideModelRequest = null;
    private Context context;

    private int mPlaceHolderResId = -1;

    /**
     * Construct a standard ImageLoader object.
     */
    public ImageLoader(Context context) {
        VariableWidthImageLoader imageLoader = new VariableWidthImageLoader(context);
        mGlideModelRequest = Glide.with(context).using(imageLoader);
        this.context = context;
    }

    /**
     * Construct an ImageLoader with a default placeholder drawable.
     */
    public ImageLoader(Context context, int placeHolderResId) {
        this(context);
        mPlaceHolderResId = placeHolderResId;
    }

    /**
     * Load an image from a url into an ImageView using the default placeholder
     * drawable if available.
     * @param url The web URL of an image.
     * @param imageView The target ImageView to load the image into.
     * @param requestListener A listener to monitor the request result.
     */
    public void loadImage(String url, ImageView imageView, RequestListener<String, Bitmap> requestListener, boolean circle, boolean thumbnail) {
        loadImage(url, imageView, requestListener, null, false, circle, thumbnail);
    }

    /**
     * Load an image from a url into an ImageView using the given placeholder drawable.
     *
     * @param url The web URL of an image.
     * @param imageView The target ImageView to load the image into.
     * @param requestListener A listener to monitor the request result.
     * @param placholderOverride A placeholder to use in place of the default placholder.
     */
    public void loadImage(String url, ImageView imageView, RequestListener<String, Bitmap> requestListener,
                          Drawable placholderOverride, boolean circle, boolean thumbnail) {
        loadImage(url, imageView, requestListener, placholderOverride, false /*crop*/, circle, thumbnail);
    }

    /**
     * Load an image from a url into an ImageView using the default placeholder
     * drawable if available.
     * @param url The web URL of an image.
     * @param imageView The target ImageView to load the image into.
     * @param requestListener A listener to monitor the request result.
     * @param placeholderOverride A drawable to use as a placeholder for this specific image.
     *                            If this parameter is present, {@link #mPlaceHolderResId}
     *                            if ignored for this request.
     */
    public void loadImage(final String url, final ImageView imageView, final RequestListener<String, Bitmap> requestListener,
                          final Drawable placeholderOverride, final boolean crop, final boolean circle, final boolean thumbnail) {
        BitmapRequestBuilder request = beginImageLoad(url, requestListener, crop, circle)
                    .diskCacheStrategy(DiskCacheStrategy.ALL);
        if (placeholderOverride != null) {
            request.placeholder(placeholderOverride);
        } else if (mPlaceHolderResId != -1) {
            request.placeholder(mPlaceHolderResId);
        }
        if(thumbnail){
            request = request.override(64, 64);
        }
        request.into(imageView);
    }

    public BitmapRequestBuilder beginImageLoad(String url, RequestListener<String, Bitmap> requestListener,
                               boolean crop, boolean circle) {
        BitmapRequestBuilder builder =
             mGlideModelRequest.load(url)
                .asBitmap() // don't allow animated GIFs
                .listener(requestListener)
                .centerCrop();

        if(circle){
            builder = builder.transform(new GlideCircleTransform(this.context));
        }
        return builder;
    }

    /**
     * Load an image from a url into the given image view using the default placeholder if
     * available.
     * @param url The web URL of an image.
     * @param imageView The target ImageView to load the image into.
     */
    public void loadImage(String url, ImageView imageView, boolean circle, boolean thumbnail) {
        loadImage(url, imageView, false /*crop*/, circle, thumbnail);
    }

    /**
     * Load an image from a uri stream into the given image view
     * @param uri   The uri of a stream
     * @param imageView The target ImageView to load the image into.
     * @param circle    Whether transform into a circle or not
     * @param thumbnail Whether transform into a thumbnail
     */
    public void loadImageByUriStream(final String uri, final ImageView imageView, boolean circle, boolean thumbnail){
        BitmapRequestBuilder builder = Glide.with(context.getApplicationContext())
                .using(new StreamUriLoader(context.getApplicationContext()))
                .load(Uri.parse(uri))
                .asBitmap()
                .centerCrop()
                .diskCacheStrategy(DiskCacheStrategy.ALL);
        if(mPlaceHolderResId != -1) {
            builder = builder.placeholder(mPlaceHolderResId);
        }
        if(thumbnail) {
            builder = builder.override(64, 64);
        }
        builder.into(imageView);
    }

    /**
     * Load an image from a uri stream into the given image view
     * @param resId   The resource id
     * @param imageView The target ImageView to load the image into.
     * @param circle    Whether transform into a circle or not
     * @param thumbnail Whether transform into a thumbnail
     */
    public void loadImageByResources(final int resId, final ImageView imageView, boolean circle, boolean thumbnail){
        BitmapRequestBuilder builder = Glide.with(context.getApplicationContext())
                .using(new StreamResourceLoader(context.getApplicationContext()))
                .load(resId)
                .asBitmap()
                .centerCrop()
                .diskCacheStrategy(DiskCacheStrategy.ALL);
        if(circle){
            builder = builder.transform(new GlideCircleTransform(this.context));
        }
        if(thumbnail) {
            builder = builder.override(64, 64);
        }
        builder.into(imageView);
    }

    public void loadRoundCornerImage(final String url, final ImageView imageView, int radius){
        BitmapRequestBuilder builder =
                mGlideModelRequest.load(url)
                        .asBitmap() // don't allow animated GIFs
                        .listener(null)
                        .centerCrop()
                        .diskCacheStrategy(DiskCacheStrategy.ALL);

        builder = builder.transform(new GlideRoundCornerImageTransform(this.context, radius));
        builder.into(imageView);
    }

    /**
     * Load an image from a url into an ImageView using the default placeholder
     * drawable if available.
     * @param url The web URL of an image.
     * @param imageView The target ImageView to load the image into.
     * @param crop True to apply a center crop to the image.
     */
    public void loadImage(String url, ImageView imageView, boolean crop, boolean circle, boolean thumbnail) {
        loadImage(url, imageView, null, null, crop, circle, thumbnail);
    }

    private static class VariableWidthImageLoader extends BaseGlideUrlLoader<String> {
        private static final Pattern PATTERN = Pattern.compile(".*__w(-\\d+)+__.*");

        public VariableWidthImageLoader(Context context) {
            super(context, urlCache);
        }

        public String getId(String model) {
            return model;
        }

        /**
         * If the URL contains a special variable width indicator (eg "__w-200-400-800__")
         * we get the buckets from the URL (200, 400 and 800 in the example) and replace
         * the URL with the best bucket for the requested width (the bucket immediately
         * larger than the requested width).
         */
        @Override
        protected String getUrl(String model, int width, int height) {
            Matcher m = PATTERN.matcher(model);
            int bestBucket = 0;
            if (m.find()) {
                String[] found = m.group(1).split("-");
                for (String bucketStr : found) {
                    bestBucket = Integer.parseInt(bucketStr);
                    if (bestBucket >= width) {
                        // the best bucket is the first immediately bigger than the requested width
                        break;
                    }
                }
                if (bestBucket > 0) {
                    model = m.replaceFirst("w"+bestBucket);
                    Log.i(TAG, "width=" + width + ", URL successfully replaced by " + model);
                }
            }
            return model;
        }
    }

    private static class GlideCircleTransform extends BitmapTransformation {
        public GlideCircleTransform(Context context) {
            super(context);
        }
        @Override
        protected Bitmap transform(BitmapPool pool, Bitmap source, int outWidth, int outHeight) {
            return ImageAndAnimateUtils.getCircularBitmapImage(source);
        }
        @Override
        public String getId() {
            return "Glide_Circle_Transformation";
        }
    }

    private static class GlideRoundCornerImageTransform extends BitmapTransformation {
        private int radius;
        public GlideRoundCornerImageTransform(Context context, int radius) {
            super(context);
            this.radius = radius;
        }
        @Override
        protected Bitmap transform(BitmapPool pool, Bitmap source, int outWidth, int outHeight) {
            return ImageAndAnimateUtils.getRoundedCornerBitmap(source, radius);
        }
        @Override
        public String getId() {
            return "Glide_Round_Corner_Transformation";
        }
    }
}
